using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Transforms;

namespace Game.Core
{
    public unsafe partial class AttackSystem : SystemBase
    {
        EndSimulationEntityCommandBufferSystem ECBSystem;
        EntityCommandBuffer buffer;
        
        NativeArray<Entity> Entities;
        ComponentLookup<Damageable> Damageables;
        ComponentLookup<LocalTransform> Positions;
        BufferLookup<PropertyModifier> PropertyModifiers;

        [BurstCompile]
        protected override void OnCreate()
        {
            ECBSystem = World.GetOrCreateSystemManaged<EndSimulationEntityCommandBufferSystem>();
            
            InitSearchTargetQuery();
            InitMoveToAttackRangeQuery();
        }

        protected override void OnUpdate()
        {
            buffer = ECBSystem.CreateCommandBuffer();
            
            // Dependency = PrepareData(Dependency);
            Entities = m_DamageableQuery.ToEntityArrayAsync(Allocator.TempJob, out var entitiesHandle);
            Dependency = JobHandle.CombineDependencies(Dependency, entitiesHandle);

            Damageables = GetComponentLookup<Damageable>(true);
            Positions = GetComponentLookup<LocalTransform>(true);
            PropertyModifiers = GetBufferLookup<PropertyModifier>();
            
            
            Dependency = ScheduleSearchTargetJob(Dependency);
            Dependency = ScheduleMoveToAttackRangeJob(Dependency);
            Dependency = ScheduleAttackTargetJob(Dependency);
            
            // ECBSystem.AddJobHandleForProducer(Dependency);
        }
        

        #region SearchTarget
        EntityQuery m_AttackableQuery;
        EntityQuery m_DamageableQuery;
        
        public void InitSearchTargetQuery()
        {
            var builder = new EntityQueryBuilder(Allocator.Temp)
                .WithAllRW<Attackable>()
                .WithAll<LocalTransform>();
            // builder.AddAll(ComponentType.ReadWrite<Attackable>());
            // builder.AddAll(ComponentType.ReadOnly<LocalTransform>());
            // builder.FinalizeQuery();
            m_AttackableQuery = GetEntityQuery(builder);
            builder.Dispose();

            builder = new EntityQueryBuilder(Allocator.Temp)
                .WithAll<Damageable>()
                .WithAll<LocalTransform>()
                .WithAllRW<PropertyModifier>();
            // builder.AddAll(ComponentType.ReadOnly<Damageable>());
            // builder.AddAll(ComponentType.ReadOnly<LocalTransform>());
            // builder.AddAll(ComponentType.ReadWrite<PropertyModifier>());
            // builder.FinalizeQuery();
            m_DamageableQuery = GetEntityQuery(builder);
            builder.Dispose();
        }
        
        private JobHandle PrepareData(JobHandle handle)
        {
            Entities = m_DamageableQuery.ToEntityArrayAsync(Allocator.TempJob, out var entitiesHandle);
            handle = JobHandle.CombineDependencies(handle, entitiesHandle);

            Damageables = GetComponentLookup<Damageable>(true);
            Positions = GetComponentLookup<LocalTransform>(true);
            PropertyModifiers = GetBufferLookup<PropertyModifier>();

            return handle;
        }

        public JobHandle ScheduleSearchTargetJob(JobHandle handle)
        {
            var searchJob = new SearchTargetJob();

            searchJob.Entities = Entities;
            searchJob.Damageables = Damageables;
            searchJob.Positions = Positions;
            // m_DamageableQuery.ToComponentDataArrayAsync<Translation>(Allocator.TempJob, out var positionJob);
            // handle = JobHandle.CombineDependencies(handle, positionJob);
            
            handle = searchJob.ScheduleParallel(m_AttackableQuery, handle);
            
            searchJob.Entities.Dispose(handle);

            return handle;
        }
       
        #endregion

        #region MoveToAttackRange
        
        EntityQuery m_MovableQuery;
        public void InitMoveToAttackRangeQuery()
        {
            var builder = new EntityQueryBuilder(Allocator.Temp)
                .WithAll<Attackable>()
                .WithAllRW<Movable>()
                .WithAll<LocalTransform>();
            // builder.AddAll(ComponentType.ReadOnly<Attackable>());
            // builder.AddAll(ComponentType.ReadWrite<Movable>());
            // builder.AddAll(ComponentType.ReadOnly<LocalTransform>());
            // builder.FinalizeQuery();
            m_MovableQuery = GetEntityQuery(builder);
            builder.Dispose();
        }

        public JobHandle ScheduleMoveToAttackRangeJob(JobHandle handle)
        {
            var job = new MoveToAttackRangeJob();
            job.Positions = Positions;
            handle = job.ScheduleParallel(m_MovableQuery, handle);
            return handle;
        }
       
        #endregion

        #region AttackTarget

        protected JobHandle ScheduleAttackTargetJob(JobHandle handle)
        {
            var job = new AttackTargetJob();
            // job.ECBParallelWriter = buffer.AsParallelWriter();
            job.Positions = GetComponentLookup<LocalTransform>(true);
            job.Damageables = Damageables;
            job.PropertyModifiers = PropertyModifiers;
            handle = job.Schedule(handle);
            return handle;
        }

        #endregion
    }
}